package com.hongyi.common.saToken.utils;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hongyi.common.framework.constant.Constants;
import com.hongyi.common.framework.domain.LoginUser;
import com.hongyi.common.framework.utils.string.ConvertUtils;
import com.hongyi.common.framework.utils.common.ObjectUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.function.Supplier;

/**
 * 登录工具类
 * <pre>
 *     1.用户登录;
 *     2.获取用户登录信息:
 *     3.用户登出;
 * </pre>
 *
 * @author DingHao
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LoginUtils {

    /**
     * 存储用户信息的key
     */
    public static final String LOGIN_USER_KEY = "loginUser";

    /**
     * 存储用户id的key
     */
    public static final String USER_KEY = "userId";

    /**
     * 登录系统
     *
     * @param loginUser 登录用户信息
     * @param model     配置参数
     */
    public static void login(LoginUser loginUser, SaLoginModel model) {
        //创建请求作用域的读取值对象,存储相关用户信息
        SaStorage storage = SaHolder.getStorage();
        storage.set(LOGIN_USER_KEY, loginUser);
        storage.set(USER_KEY, loginUser.getUserId());
        //设置登录参数
        SaLoginModel saLoginModel = ObjectUtils.defaultIfNull(model, new SaLoginModel());
        String user = loginUser.getUserType() + ":" + loginUser.getUserId();
        //执行用户登录
        StpUtil.login(user, saLoginModel.setExtra(USER_KEY, loginUser.getUserId()));
        //设置会话参数过期时间与用户信息
        SaSession tokenSession = StpUtil.getTokenSession();
        //tokenSession.updateTimeout(model.getTimeout());
        tokenSession.set(LOGIN_USER_KEY, loginUser);
    }

    /**
     * 获取用户对象
     */
    public static LoginUser getLoginUser() {
        return (LoginUser) getStorage(LOGIN_USER_KEY, () -> {
            SaSession tokenSession = StpUtil.getTokenSession();
            if (ObjectUtils.isNull(tokenSession)) {
                return null;
            }
            return tokenSession.get(LOGIN_USER_KEY);
        });
    }

    /**
     * 获取用户基于token
     */
    public static LoginUser getLoginUser(String token) {
        SaSession session = StpUtil.getTokenSessionByToken(token);
        if (ObjectUtil.isNull(session)) {
            return null;
        }
        return (LoginUser) session.get(LOGIN_USER_KEY);
    }

    /**
     * 重置用户对象
     */
    public static void resetUser(LoginUser loginUser) {
        //设置会话参数过期时间与用户信息
        SaSession tokenSession = StpUtil.getTokenSession();
        //tokenSession.updateTimeout(model.getTimeout());
        tokenSession.set(LOGIN_USER_KEY, loginUser);
    }

    /**
     * 获取用户Id
     */
    public static Long getUserId() {
        return ConvertUtils.toLong(getStorage(USER_KEY, () -> StpUtil.getExtra(USER_KEY)));
    }

    /**
     * 获取用户名
     */
    public static String getUserName() {
        return getLoginUser().getUsername();
    }

    /**
     * 根据key获取SaStorage存储对象
     *
     * <p>描述：优先根据key获取SaStorage存储对象,如果获取不到就在tokenSession获取</p>
     *
     * @param key    缓存的key
     * @param method 获取缓存对象的方法
     */
    public static Object getStorage(String key, Supplier<Object> method) {
        Object object = SaHolder.getStorage().get(key);
        if (ObjectUtils.isNull(object)) {
            Object resultObj = method.get();
            SaHolder.getStorage().set(key, resultObj);
            return resultObj;
        } else {
            return object;
        }
    }

    /**
     * 是否为管理员
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId) {
        return Constants.ADMIN_ID.equals(userId);
    }

    /**
     * 登出系统
     *
     * <p>描述：删除已登录的token</p>
     */
    public static void logout() {
        StpUtil.logout();
    }

}
